package com.example.videocompressors;
import ohos.media.codec.Codec;
import ohos.media.common.BufferInfo;
import ohos.media.common.Format;
import ohos.media.common.Source;
import ohos.media.extractor.Extractor;
import ohos.media.muxer.Muxer;
import ohos.media.photokit.metadata.AVMetadataHelper;
import com.example.videocompressors.listner.SlimProgressListener;
import com.example.videocompressors.muxer.CodecInputSurface;

import java.io.File;
import java.nio.ByteBuffer;

/**
 * trans code for video to mp4
 * mediacodec support  3gp and mp4
 */
public class VideoSlimEncoder {

    private static final String TAG = "VideoSlimEncoder";
    private static final boolean VERBOSE = true;           // lots of logging
    public String path;
    private String outputPath;
    public final static String MIME_TYPE = "video/avc";
    private BufferInfo mBufferInfo;
    private Muxer mMuxer;
    private Codec mEncoder;
    private Codec mDecoder;
    private int mTrackIndex;
    private CodecInputSurface mInputSurface;
    // size of a frame, in pixels
    private int mWidth = -1;
    private int mHeight = -1;
    // bit rate, in bits per second
    private int mBitRate = -1;
    private static int FRAME_RATE = 25;               // 15fps
    private static int IFRAME_INTERVAL = 10;          // 10 seconds between I-frames
    private static final int MEDIATYPE_NOT_AUDIO_VIDEO = -233;  //媒体类型不是音频视频
    private final int TIMEOUT_USEC = 2500;


    public  VideoSlimEncoder () {

    }


    /***
     * trans video and audio  by mediacodec
     *
     * */
    public boolean convertVideo(final String sourcePath, String destinationPath, int nwidth, int nheight, int nbitrate, SlimProgressListener listener) {

        this.path = sourcePath;
        this.outputPath = destinationPath;

        if (checkParmsError(sourcePath, destinationPath, nwidth, nheight, nbitrate)) {
            return false;
        }

        //get origin video info
        AVMetadataHelper retriever = new AVMetadataHelper();
        retriever.setSource(path);
   /*     String width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
        String height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
        String rotation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
        long duration = Long.valueOf(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)) * 1000;*/
        String width = retriever.resolveMetadata(AVMetadataHelper.AV_KEY_VIDEO_WIDTH);
        String height = retriever.resolveMetadata(AVMetadataHelper.AV_KEY_VIDEO_HEIGHT);
        String rotation = retriever.resolveMetadata(AVMetadataHelper.AV_KEY_VIDEO_ROTATION);
        long duration = Long.valueOf(retriever.resolveMetadata(AVMetadataHelper.AV_KEY_DURATION)) * 1000;
        long startTime = -1;
        long endTime = -1;
        int originalWidth = Integer.valueOf(width);
        int originalHeight = Integer.valueOf(height);
        mBitRate = nbitrate;
        mWidth = nwidth;
        mHeight = nheight;
        boolean error = false;
        long videoStartTime = -1;

        long time = System.currentTimeMillis();

        File cacheFile = new File(destinationPath);
        File inputFile = new File(path);
        if (!inputFile.canRead()) {

            return false;
        }

        Extractor extractor = null;
        Extractor mAudioExtractor = null;

        try {
            // video MediaExtractor
            extractor = new Extractor();
          //  extractor.setDataSource(inputFile.toString());
            extractor.setSource(new Source(inputFile.toString()));
            // audio MediaExtractor
            mAudioExtractor = new Extractor();
           // mAudioExtractor.setDataSource(inputFile.toString());
            mAudioExtractor.setSource(new Source(inputFile.toString()));
            try {
               // mMuxer = new Muxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
                mMuxer = new Muxer(outputPath, Muxer.MediaFileFormat.FORMAT_MPEG4);
            } catch (Exception ioe) {


                throw new RuntimeException("MediaMuxer creation failed", ioe);
            }

            int muxerAudioTrackIndex = 0;


            int audioIndex = selectTrack(mAudioExtractor, true);
            if (audioIndex >= 0) {
                mAudioExtractor.specifyStream(audioIndex);
             //   mAudioExtractor.seekTo(0, Extractor.SEEK_TO_PREVIOUS_SYNC);
                mAudioExtractor.rewindTo(0, Extractor.REWIND_TO_PREVIOUS_SYNC);
                Format trackFormat = mAudioExtractor.getStreamFormat(audioIndex);
                muxerAudioTrackIndex = mMuxer.appendTrack(trackFormat);

               // extractor.unselectTrack(muxerAudioTrackIndex);
            }

            /**
             * mediacodec + surface + opengl
             * */
            if (nwidth != originalWidth || nheight != originalHeight) {

                int videoIndex = selectTrack(extractor, false);

                if (videoIndex >= 0) {

                    long videoTime = -1;
                    boolean outputDone = false;
                    boolean inputDone = false;
                    boolean decoderDone = false;
                    int swapUV = 0;
                    int videoTrackIndex = MEDIATYPE_NOT_AUDIO_VIDEO;


                    extractor.specifyStream(videoIndex);
                    if (startTime > 0) {
                        extractor.rewindTo(startTime, Extractor.REWIND_TO_PREVIOUS_SYNC);
                    } else {
                        extractor.rewindTo(0, Extractor.REWIND_TO_PREVIOUS_SYNC);
                    }
               Format inputFormat = extractor.getStreamFormat(videoIndex);


                    /**
                     ** init mediacodec  / encoder and decoder
                     **/
                    prepareEncoder(inputFormat);


                    ByteBuffer[] decoderInputBuffers = null;
                    ByteBuffer[] encoderOutputBuffers = null;

                    while (!outputDone) {
                        //解码input是否结束
                        if (!inputDone) {
                            boolean eof = false;
                            //int index = extractor.getSampleTrackIndex();
                            int index = extractor.getStreamId();
                            if (index == videoIndex) {
                               // int inputBufIndex = mDecoder.dequeueInputBuffer(TIMEOUT_USEC);
                              // if (inputBufIndex >= 0) {
                                ByteBuffer inputBuf;
                                    //解码input

                                      //  inputBuf = mDecoder.getInputBuffer(inputBufIndex);
                                    inputBuf=mDecoder.getAvailableBuffer(TIMEOUT_USEC);
                                    //读取数据放入inputBuf中
                                    int chunkSize = extractor.readBuffer(inputBuf, 0);
                                    //写入input结束表示
                                    if (chunkSize < 0) {
                                      //  mDecoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, BufferInfo.BUFFER_TYPE_END_OF_STREAM);
                                        BufferInfo bufferInfo=new BufferInfo();
                                        bufferInfo.setInfo(0,0,0L,BufferInfo.BUFFER_TYPE_END_OF_STREAM);
                                        mDecoder.writeBuffer(inputBuf,bufferInfo);
                                        inputDone = true;
                                    } else {
                                        //写入解码器一帧数据
                                        //mDecoder.queueInputBuffer(inputBufIndex, 0, chunkSize, extractor.getSampleTime(), 0);
                                        BufferInfo bufferInfo=new BufferInfo();
                                        bufferInfo.setInfo(0,0,0L,BufferInfo.BUFFER_TYPE_END_OF_STREAM);
                                        mDecoder.writeBuffer(inputBuf,bufferInfo);
                                        extractor.next();
                                    }
                               // }
                            } else if (index == -1) {
                                eof = true;
                            }
                            //解码input读到末尾 将结束标识添加入栈
                            if (eof) {
                              //  int inputBufIndex = mDecoder.dequeueInputBuffer(TIMEOUT_USEC);
                                ByteBuffer inputBufIndex = mDecoder.getAvailableBuffer(TIMEOUT_USEC);
                               // if (inputBufIndex >= 0) {
                                if (inputBufIndex !=null) {
                                   // mDecoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, BufferInfo.BUFFER_TYPE_END_OF_STREAM);
                                    BufferInfo bufferInfo=new BufferInfo();
                                    bufferInfo.setInfo(0,0,0L,BufferInfo.BUFFER_TYPE_END_OF_STREAM);
                                    mDecoder.writeBuffer(inputBufIndex,bufferInfo);
                                    inputDone = true;
                                }
                            }
                        }

                         boolean decoderOutputAvailable = !decoderDone;
                        boolean  encoderOutputAvailable = true;
                    //解码编码未完成
                        while (decoderOutputAvailable || encoderOutputAvailable) {

                            //int encoderStatus = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);

                             ByteBuffer encoderStatus= mEncoder.getAvailableBuffer(TIMEOUT_USEC);
                            //判断解码标识 解码output结束
                            //调用超时
                            if (encoderStatus ==null) {
                                encoderOutputAvailable = false;
                                //一个outbuffer写入结束
                            }
                            //视频轨道解码结束
                            //format配置改变
                        /*    else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                                MediaFormat newFormat = mEncoder.getOutputFormat();
                                if (videoTrackIndex == MEDIATYPE_NOT_AUDIO_VIDEO) {
                                    videoTrackIndex = mMuxer.appendTrack(newFormat);
                                    mTrackIndex = videoTrackIndex;
                                    mMuxer.start();
                                }
                            }*/
                          else if (videoTrackIndex == MEDIATYPE_NOT_AUDIO_VIDEO) {
                                Format newFormat = mEncoder.getBufferFormat(encoderStatus);
                                videoTrackIndex = mMuxer.appendTrack(newFormat);
                                mTrackIndex = videoTrackIndex;
                                mMuxer.start();
                            }
                            //错误
                            else if (encoderStatus== null) {
                                throw new RuntimeException("unexpected result from mEncoder.dequeueOutputBuffer: " + encoderStatus);
                            }
                            //视频压缩
                            else {
                                ByteBuffer encodedData=encoderStatus;

                                    //编码outbuffer
                                  //  encodedData = mEncoder.getAvailableBuffer(encoderStatus);
                                //错误
                                if (encodedData == null) {
                                    throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
                                }
                                if (mBufferInfo.size > 1) {
                                    //configure()已调用
                                    if ((mBufferInfo.bufferType & BufferInfo.BUFFER_TYPE_CODEC_CONFIG) == 0) {
                                        mMuxer.writeBuffer(videoTrackIndex, encodedData, mBufferInfo);
                                    }
                                    else if (videoTrackIndex == MEDIATYPE_NOT_AUDIO_VIDEO) {
                                        byte[] csd = new byte[mBufferInfo.size];
                                        encodedData.limit(mBufferInfo.offset + mBufferInfo.size);
                                        encodedData.position(mBufferInfo.offset);
                                        encodedData.get(csd);
                                        ByteBuffer sps = null;
                                        ByteBuffer pps = null;
                                        for (int a = mBufferInfo.size - 1; a >= 0; a--) {
                                            if (a > 3) {
                                                if (csd[a] == 1 && csd[a - 1] == 0 && csd[a - 2] == 0 && csd[a - 3] == 0) {
                                                    sps = ByteBuffer.allocate(a - 3);
                                                    pps = ByteBuffer.allocate(mBufferInfo.size - (a - 3));
                                                    sps.put(csd, 0, a - 3).position(0);
                                                    pps.put(csd, a - 3, mBufferInfo.size - (a - 3)).position(0);
                                                    break;
                                                }
                                            } else {
                                                break;
                                            }
                                        }
                                 //创建压缩后的format 并将解码后的数据填入
                                      // Format newFormat = MediaFormat.createVideoFormat(MIME_TYPE, nwidth, nheight);
                                        Format newFormat=new Format();
                                        newFormat.putStringValue(Format.MIME, MIME_TYPE);
                                        newFormat.putIntValue(Format.WIDTH, nwidth);
                                        newFormat.putIntValue(Format.HEIGHT, nheight);

                                        if (sps != null && pps != null) {
                                            newFormat.setObjectFormat("csd-0", sps);
                                            newFormat.setObjectFormat("csd-1", pps);
                                        }
                                        videoTrackIndex = mMuxer.appendTrack(newFormat);
                                        mMuxer.start();
                                    }
                                }
                                outputDone = (mBufferInfo.bufferType & BufferInfo.BUFFER_TYPE_END_OF_STREAM) != 0;
                                //mEncoder.releaseOutputBuffer(encoderStatus, false);
                            }
                            if (encoderStatus != null) {
                                continue;
                            }
//??????????????????????????????????????????????????
                            if (!decoderDone) {
                               // ByteBuffer decoderStatus = mDecoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
                                ByteBuffer decoderStatus = mDecoder.getAvailableBuffer( TIMEOUT_USEC);
                                if (decoderStatus == null) {
                                    decoderOutputAvailable = false;
                                }
                              else if (decoderStatus == null) {
                                    throw new RuntimeException("unexpected result from mDecoder.dequeueOutputBuffer: " + decoderStatus);
                                } else {
                                    boolean doRender = false;

                                    doRender = mBufferInfo.size != 0;

                                    if (endTime > 0 && mBufferInfo.timeStamp >= endTime) {
                                        inputDone = true;
                                        decoderDone = true;
                                        doRender = false;
                                        mBufferInfo.bufferType |= BufferInfo.BUFFER_TYPE_END_OF_STREAM;
                                    }
                                    if (startTime > 0 && videoTime == -1) {
                                        if (mBufferInfo.timeStamp < startTime) {
                                            doRender = false;
                                        } else {
                                            videoTime = mBufferInfo.timeStamp;
                                        }
                                    }
                                  //  mDecoder.releaseOutputBuffer(decoderStatus, doRender);
                                    if (doRender) {
                                        boolean errorWait = false;
                                        try {
                                            mInputSurface.awaitNewImage();
                                        } catch (Exception e) {
                                            errorWait = true;

                                        }
                                        if (!errorWait) {

                                            mInputSurface.drawImage();
                                            mInputSurface.setPresentationTime(mBufferInfo.timeStamp * 1000);

                                            if (listener != null) {
                                                listener.onProgress((float) mBufferInfo.timeStamp / (float) duration * 100);
                                            }

                                            mInputSurface.swapBuffers();

                                        }
                                    }
                                    if ((mBufferInfo.bufferType & BufferInfo.BUFFER_TYPE_END_OF_STREAM) != 0) {
                                        decoderOutputAvailable = false;
                                       // mEncoder.signalEndOfInputStream();
                                       // mEncoder.();
                                  /*      BufferInfo bufferInfo=new BufferInfo();
                                        bufferInfo.setInfo(0,0,0L,BufferInfo.BUFFER_TYPE_END_OF_STREAM);
                                        mDecoder.writeBuffer(mDecoder.get,bufferInfo);*/

                                    }
                                }
                            }
                        }
                    }
                    if (videoTime != -1) {
                        videoStartTime = videoTime;
                    }


                }


                extractor.unspecifyStream(videoIndex);

            } else {

                long videoTime = simpleReadAndWriteTrack(extractor, mMuxer, mBufferInfo, startTime, endTime, cacheFile, false);
                if (videoTime != -1) {
                    videoStartTime = videoTime;
                }
            }

//            if (!error) {
//                Log.e(TAG,"startaudiorecord");
//                simpleReadAndWriteTrack(extractor, mMuxer, mBufferInfo, videoStartTime, endTime, cacheFile, true);
//            }

            writeAudioTrack(mAudioExtractor, mMuxer, mBufferInfo, videoStartTime, endTime, cacheFile, muxerAudioTrackIndex);

        } catch (Exception e) {
            error = true;

        } finally {
            if (extractor != null) {
                extractor.release();
                extractor = null;
            }


            if (mAudioExtractor != null) {
                mAudioExtractor.release();
                mAudioExtractor = null;
            }

        }


        releaseCoder();

        if(error)
            return  false;
        else
            return true;
    }


    private boolean checkParmsError(String sourcePath, String destinationPath, int nwidth, int nheight, int nbitrate) {


        if (nwidth <= 0 || nheight <= 0 || nbitrate <= 0)
            return true;
        else
            return false;

    }

//合并写入
    private long simpleReadAndWriteTrack(Extractor extractor, Muxer mediaMuxer, BufferInfo info, long start, long end, File file, boolean isAudio) throws Exception {
        int trackIndex = selectTrack(extractor, isAudio);
        if (trackIndex >= 0) {
            //extractor.selectTrack(trackIndex);
            extractor.specifyStream(trackIndex);
            Format trackFormat = extractor.getStreamFormat(trackIndex);
            int muxerTrackIndex = mediaMuxer.appendTrack(trackFormat);

            if(!isAudio)
             mediaMuxer.start();

          //  int maxBufferSize = trackFormat.getIntValue(Format.KEY_MAX_INPUT_SIZE);
            int maxBufferSize = trackFormat.getIntValue(Format.MAX_INPUT_SIZE);
            boolean inputDone = false;
            if (start > 0) {
                extractor.rewindTo(start, Extractor.REWIND_TO_PREVIOUS_SYNC);
            } else {
                extractor.rewindTo(0, Extractor.REWIND_TO_PREVIOUS_SYNC);
            }
            ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize);
            long startTime = -1;

            while (!inputDone) {

                boolean eof = false;
                int index = extractor.getStreamId();
                if (index == trackIndex) {
                    info.size = extractor.readBuffer(buffer, 0);
                    if (info.size < 0) {
                        info.size = 0;
                        eof = true;
                    } else {
                        info.timeStamp = extractor.getFrameTimestamp();
                        if (start > 0 && startTime == -1) {
                            startTime = info.timeStamp;
                        }
                        if (end < 0 || info.timeStamp < end) {
                            info.offset = 0;
                            info.bufferType = extractor.getFrameType();
                           // mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info);
                            mediaMuxer.writeBuffer(muxerTrackIndex, buffer, info);

                            extractor.next();
                        } else {
                            eof = true;
                        }
                    }
                } else if (index == -1) {
                    eof = true;
                }
                if (eof) {
                    inputDone = true;
                }
            }

            extractor.unspecifyStream(trackIndex);
            return startTime;
        }
        return -1;
    }

    //合并写入
    private long writeAudioTrack(Extractor extractor, Muxer mediaMuxer, BufferInfo info, long start, long end, File file,int muxerTrackIndex ) throws Exception {
        int trackIndex = selectTrack(extractor, true);
        if (trackIndex >= 0) {
            extractor.specifyStream(trackIndex);
          Format trackFormat = extractor.getStreamFormat(trackIndex);


            int maxBufferSize = trackFormat.getIntValue(Format.MAX_INPUT_SIZE);
            boolean inputDone = false;
            if (start > 0) {
                extractor.rewindTo(start, Extractor.REWIND_TO_PREVIOUS_SYNC);
            } else {
                extractor.rewindTo(0, Extractor.REWIND_TO_PREVIOUS_SYNC);
            }
            ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize);
            long startTime = -1;

            while (!inputDone) {

                boolean eof = false;
             //   int index = extractor.rewindTo();
                int index = extractor.getStreamId();
                if (index == trackIndex) {
                    info.size = extractor.readBuffer(buffer, 0);

                    if (info.size < 0) {
                        info.size = 0;
                        eof = true;
                    } else {
                        info.timeStamp = extractor.getFrameTimestamp();
                        if (start > 0 && startTime == -1) {
                            startTime = info.timeStamp;
                        }
                        if (end < 0 || info.timeStamp < end) {
                            info.offset = 0;
                           // info.flags = extractor.getSampleFlags();
                            info.bufferType=extractor.getFrameType();
                            mediaMuxer.writeBuffer(muxerTrackIndex, buffer, info);
                            extractor.next();
                        } else {
                            eof = true;
                        }
                    }
                } else if (index == -1) {
                    eof = true;
                }
                if (eof) {
                    inputDone = true;
                }
            }

            extractor.unspecifyStream(trackIndex);
            return startTime;
        }
        return -1;
    }
    

    private int selectTrack(Extractor extractor, boolean audio) {
        //int numTracks = extractor.getTrackCount();
        int numTracks=  extractor.getTotalStreams();
        for (int i = 0; i < numTracks; i++) {
            Format format = extractor.getStreamFormat(i);
            String mime = format.getStringValue(Format.MIME);
            if (audio) {
                if (mime.startsWith("audio/")) {
                    return i;
                }
            } else {
                if (mime.startsWith("video/")) {
                    return i;
                }
            }
        }
        return MEDIATYPE_NOT_AUDIO_VIDEO;
    }


    /**
     * Configures encoder and muxer state, and prepares the input Surface.
     * 配置编码器和复用器状态，并准备输入 Surface。
     */
    private void prepareEncoder(Format inputFormat) {
        mBufferInfo = new BufferInfo();

        //Format format = Format.createVideoFormat(MIME_TYPE, mWidth, mHeight);
        Format format=new Format();
        format.putStringValue(Format.MIME, Format.VIDEO_AVC);
        format.putIntValue(Format.WIDTH, mWidth);
        format.putIntValue(Format.HEIGHT, mHeight);
        // Set some properties.  Failing to specify some of these can cause the MediaCodec
        // configure() call to throw an unhelpful exception.
/*        format.setObjectFormat(MediaFormat.KEY_COLOR_FORMAT,
                MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);*/
        format.setObjectFormat(Format.COLOR_MODEL,2130708361);
       // format.setObjectFormat(Format.KEY_BIT_RATE, mBitRate);
        format.setObjectFormat(Format.BIT_RATE, mBitRate);
       // format.setObjectFormat(Format.KEY_FRAME_RATE, FRAME_RATE);
        format.setObjectFormat(Format.KEY_FRAME_RATE_SCOPE, FRAME_RATE);
        //format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
        format.setObjectFormat(Format.FRAME_INTERVAL, IFRAME_INTERVAL);

        // Create a MediaCodec encoder, and configure it with our format.  Get a Surface
        // we can use for input and wrap it with a class that handles the EGL work.
        //
        // If you want to have two EGL contexts -- one for display, one for recording --
        // you will likely want to defer instantiation of CodecInputSurface until after the
        // "display" EGL context is created, then modify the eglCreateContext call to
        // take eglGetCurrentContext() as the share_context argument.
        try {
            mEncoder = Codec.createEncoder();
            Format format1=new Format();
            format1.putStringValue(Format.MIME,MIME_TYPE);
            mEncoder.setCodecFormat(format1);
        } catch (Exception e) {
            e.printStackTrace();
        }
       // mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        mInputSurface = new CodecInputSurface(mEncoder.obtainInputSurface());
        mInputSurface.makeCurrent();
        mEncoder.start();

        try {
            mEncoder = Codec.createEncoder();
            Format format2=new Format();
            format2.putStringValue(Format.MIME,inputFormat.getStringValue(Format.MIME));
            mDecoder = Codec.createDecoder();
            mDecoder.setCodecFormat(format2);
        } catch (Exception e) {
            e.printStackTrace();
        }
        mInputSurface.createRender();
     //  mDecoder.configure(inputFormat, mInputSurface.getSurface(), null, 0);
        mDecoder.start();

        // Output filename.  Ideally this would use Context.getFilesDir() rather than a
        // hard-coded output directory.

        // Create a MediaMuxer.  We can't add the video track and start() the muxer here,
        // because our MediaFormat doesn't have the Magic Goodies.  These can only be
        // obtained from the encoder after it has started processing data.
        //
        // We're not actually interested in multiplexing audio.  We just want to convert
        // the raw H.264 elementary stream we get from MediaCodec into a .mp4 file.


        mTrackIndex = -1;
    }

    /**
     * Releases encoder resources.  May be called after partial / failed initialization.
     */
    private void releaseCoder() {
        if (VERBOSE)
            //Log.d(TAG, "releasing encoder objects");
        if (mEncoder != null) {
            mEncoder.stop();
            mEncoder.release();
            mEncoder = null;
        }
        if (mDecoder != null) {
            mDecoder.stop();
            mDecoder.release();
            mDecoder = null;
        }
        if (mInputSurface != null) {
            mInputSurface.release();
            mInputSurface = null;
        }
        if (mMuxer != null) {
            mMuxer.stop();
            mMuxer.release();
            mMuxer = null;
        }
    }


}
